package com.itcoon.transform.base.register.annotated;

import com.itcoon.transform.base.exception.AssembleException;
import com.itcoon.transform.base.annotation.AssembleModel;
import com.itcoon.transform.base.annotation.AssembleModelProperty;
import com.itcoon.transform.base.definition.ModelDefinition;
import com.itcoon.transform.base.definition.ModelPropertyDefinition;
import com.itcoon.transform.base.utils.TransformServiceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Optional;

/**
 * 注册器 —— target为带注解的接口对象
 *
 * @author Miaoxia Yu
 * @date 2020-10-26
 */
@Component
public class AnnotatedInterAssembleModelRegister implements AnnotatedAssembleModelRegister {

    public static final Logger log = LoggerFactory.getLogger(AnnotatedInterAssembleModelRegister.class);

    @Override
    public boolean support(Class<?> targetClass) {
        return targetClass.isInterface() && targetClass.getAnnotation(AssembleModel.class) != null;
    }

    @Override
    public void register(ModelDefinition modelDefinition) throws IntrospectionException {
        Class<?> targetClass = modelDefinition.getTargetClass();
        AssembleModel assembleModel = targetClass.getAnnotation(AssembleModel.class);
        Class<?> originClass = assembleModel.from();
        modelDefinition.setOriginClass(originClass);
        BeanInfo targetBeanInfo = Introspector.getBeanInfo(targetClass);
        PropertyDescriptor[] targetPropertyDescriptors = targetBeanInfo.getPropertyDescriptors();
        for (PropertyDescriptor targetPropertyDescriptor : targetPropertyDescriptors) {
            Method targetGetter = targetPropertyDescriptor.getReadMethod();
            ModelPropertyDefinition mpd = new ModelPropertyDefinition(modelDefinition);
            mpd.setTargetGetter(targetGetter);
            mpd.setTargetAttribute(targetPropertyDescriptor.getName());
            mpd.setTargetPropertyType(targetPropertyDescriptor.getPropertyType());
            Optional<AssembleModelProperty> annotationOp = Optional.ofNullable(targetGetter.getAnnotation(AssembleModelProperty.class));
            mpd.setAnnotated(annotationOp.isPresent());
            if (annotationOp.isPresent()) {
                AssembleModelProperty assembleModelProperty = annotationOp.get();
                String originAttribute  = StringUtils.isEmpty(assembleModelProperty.mapValue()) ? mpd.getTargetAttribute() : assembleModelProperty.mapValue();
                originAttribute = targetGetter.isDefault() ? null : originAttribute;
                mpd.setOriginAttribute(originAttribute);
                if(originAttribute != null){
                    // 根据originAttribute 是否包含”." 级联获取元对象的getter
                    Method originGetter = TransformServiceUtils.findGetterFromValue(originClass, originAttribute);
                    if(originGetter == null){
                        throw new AssembleException(String.format("[Transform4j] - register assemble model#%s failure, can not found originGetter from attribute#%s in origin class #%s", targetClass, originAttribute, originClass.getName()));
                    }
                    mpd.setOriginGetter(originGetter);
                }
                modelDefinition.getPropertyDefinitions().add(mpd);
            }
        }
    }
}
